import { isDate, isNumber } from "./Utils";

/**
 * 判断日期是否为有效日期
 * @since V1.2.0
 * @param value 参数
 * @return boolean true or false
 */
export function isValidDate(value: Date): boolean {
    return isDate(value) && !isNaN(value.getTime());
}

/**
 * 获取基础日期的间隔日期
 * @param interval {number} 间隔天数，正数则返回基础日期之后的日期，负数则返回基础日期之前的日期
 * @param baseDate {Date} 基础日期，如果不传则默认为今天
 * @returns {Date} 新的Date对象
 * @since V1.0.0
 */
export function getDateOfInterval(interval: number, baseDate: Date = new Date()): Date {
    if (!isNumber(interval)) {
        throw new TypeError(`Parameter [ interval ] must be of type number.`);
    }
    if (!baseDate) {
        baseDate = new Date();
    } else if (!isDate(baseDate)) {
        throw new TypeError(`Parameter [ baseDate ] must be of type Date.`);
    }
    baseDate = new Date(baseDate.toString()); // 创建一个新的Date对象
    baseDate.setDate(baseDate.getDate() + interval);
    return baseDate;
}

/**
 * 获取时间范围内的日期，包含开始日期和结束日期
 * @param startDate {Date} 开始日期
 * @param endDate {Date} 结束日期
 * @returns {Array<Date>} 日期数组
 * @since V1.0.0
 */
export function getDatesFromDateRange(startDate: Date, endDate: Date): Date[] {
    if (!isDate(startDate) || !isDate(endDate)) {
        throw new TypeError('Parameter must be of Date type.');
    }
    const dateRange = [];
    while ((endDate.getTime() - startDate.getTime()) >= 0) {
        const d = new Date(startDate.getTime()); // 以开始日期为基础日期创建一个新的日期对象
        dateRange.push(d);
        startDate.setDate(startDate.getDate() + 1);
    }
    return dateRange;
}

/**
 * 日期格式化
 * @param date {Date} 日期
 * @param fmt {string} 格式，默认格式：YYYY-MM-dd
 * @since V1.0.0
 * @version V2.0.0
 * <p>格式说明：</p>
 * <p>y或者Y：年份，yy表示两位数字年份，yyyy表示四位数字年份</p>
 * <p>M：表示月份 (0 ~ 11)</p>
 * <p>d：表示月份中的天数(1 ~ 31)</p>
 * <p>H：表示一天中的小时数 (24小时制，0 ~ 23)</p>
 * <p>h：表示一天中的小时数 (12小时制，0 ~ 12)</p>
 * <p>m：表示分钟数 (0 ~ 59)</p>
 * <p>s: 表示秒数 (0 ~ 59)</p>
 * <p>S: 表示毫秒数</p>
 * @Return 日期格式化后的string字符串
 *
 * <pre>
 * const date = new Date();
 * date.setFullYear(2022, 1, 5);
 * dateFormat(date)                             // 返回 "2022-02-05"
 * dateFormat(date, 'YYYY-MM-dd hh:mm:ss')      // 返回 "2022-02-05 16:44:11"
 * </pre>
 */
export function dateFormat(date: Date, fmt = 'YYYY-MM-dd'): string {
    if (!isDate(date)) {
        throw new TypeError('Parameter must be of Date type.');
    }
    const opt: {    //  设置正则匹配项
        [key: string]: string
    } = {
        "[Y|y]+": date.getFullYear().toString(),                     // 年
        "M+": (date.getMonth() + 1).toString(),                      // 月份
        "d+": date.getDate().toString(),                             // 日
        "H+": date.getHours().toString(),                            // 小时
        "h+": (date.getHours() >= 12 ? date.getHours() - 12 : date.getHours()).toString(),   // 小时
        "m+": date.getMinutes().toString(),                          // 分
        "s+": date.getSeconds().toString(),                          // 秒
        "q+": Math.floor((date.getMonth() + 3) / 3).toString(),   // 季度
        "S+": date.getMilliseconds().toString()                      // 毫秒
    };
    let matchRes; // 正则匹配结果
    for (const k in opt) {
        matchRes = fmt.match(new RegExp(k, 'g')); // match()方法检索正则表达式的匹配，如果没有找到任何匹配的文本，返回null，否则返回数组
        matchRes && matchRes.forEach(matchedItem => { // 如果匹配成功，则将匹配项依次替换
            fmt = fmt.replace(matchedItem, opt[k].padStart(matchedItem.length, '0'));
        });
    }
    return fmt;
}

/** 日期相关工具类 */
export class DateUtils {

    /** 检验参数是否为Date类型 */
    static isDate(arg: any): boolean {
        return isDate(arg);
    }

    /** 获取基础日期的间隔日期 */
    static getDateOfInterval(interval: number, baseDate: Date = new Date()): Date {
        return getDateOfInterval(interval, baseDate);
    }

    /** 获取时间范围内的日期，包括开始日期和结束日期 */
    static getDatesFromDateRange(startDate: Date, endDate: Date): Date[] {
        return getDatesFromDateRange(startDate, endDate);
    }

    /** 日期格式化 */
    static dateFormat(date: Date, fmt = 'YYYY-MM-dd'): string {
        return dateFormat(date, fmt);
    }
}
